#include "config.h"

#include <cstdio>
#include <iostream>
#include <string>
#if CFG_HAVE_STD_RANGES
#include <ranges>
#endif

using namespace cfg;

// 示例：更丰富的错误演示（SchemaRootNotObject、IncludeOpenError、IncludeParseError、RegexMismatch
// 等）
// - 需要启用 CFG_ENABLE_YAML 以演示文件解析路径；否则也会展示部分 schema 错误。

static void
print_error(const ConfigError & e)
{
    std::cerr << "[" << static_cast<int>(e.code) << "] " << e.message;
    if (!e.path.empty())
    {
        std::cerr << " path=";
#if CFG_HAVE_STD_RANGES
        for (char ch : e.path | std::views::join_with(std::string_view(".")))
        {
            std::cerr << ch;
        }
#else
        for (size_t i = 0; i < e.path.size(); ++i)
        {
            if (i > 0)
                std::cerr << '.';
            std::cerr << e.path[i];
        }
#endif
    }
    if (e.expected_type)
        std::cerr << " expected_type=" << static_cast<int>(*e.expected_type);
    if (e.actual_type)
        std::cerr << " actual_type=" << static_cast<int>(*e.actual_type);
    if (e.expected_pattern)
        std::cerr << " pattern=\"" << *e.expected_pattern << "\"";
    std::cerr << "\n";
}

// 函数：创建/写入文件
static std::string
create_file(const std::string & filename, const char * content)
{
    FILE * fp = std::fopen(filename.c_str(), "w");
    if (!fp)
        return {};
    std::fputs(content, fp);
    std::fclose(fp);
    return filename;
}

int
main()
{
    // 1) SchemaRootNotObject：构造一个根非对象的 schema（例如直接是字符串）
    {
        Builder b;
#ifdef CFG_ENABLE_YAML
        const std::string bad_schema = create_file("schema_not_object.yaml", "'not an object'\n");
        b.load_json_schema_file(bad_schema);
#else
        // 未启用 YAML 时，仍调用接口，内部会记录一条错误（保持兼容）。
        b.load_json_schema_file("schema_not_object.yaml");
#endif
        auto fr = b.freeze();
        if (!fr)
        {
            std::cerr << "Case SchemaRootNotObject: " << fr.error().size() << " error(s)\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

#ifdef CFG_ENABLE_YAML
    // 2) IncludeOpenError：包含一个不存在的文件
    {
        Builder b;
        b.include_file("no_such_file.yaml");
        auto fr = b.freeze();
        if (!fr)
        {
            std::cerr << "Case IncludeOpenError: " << fr.error().size() << " error(s)\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    // 3) IncludeParseError：写入一个语法错误的 YAML，再尝试 include
    {
        const std::string bad_path = create_file("syntax_bad.yaml", "a: [1, 2\n"); // 缺少右方括号
        Builder b;
        b.include_file(bad_path);
        auto fr = b.freeze();
        if (!fr)
        {
            std::cerr << "Case IncludeParseError: " << fr.error().size() << " error(s)\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }
#endif

    // 4) RegexMismatch：添加一个正则规则，然后提供不匹配的值
    {
        Builder b;
        SchemaRule r;
        r.path = "user.email";
        r.expected_type = SchemaValueType::String;
        r.regex_pattern = "^\\\
w+@example\\.com$"; // 只允许 @example.com
        b.add_schema_rule(r);
        b.set("user.email", std::string("alice@other.com"));
        auto fr = b.freeze();
        if (!fr)
        {
            std::cerr << "Case RegexMismatch: " << fr.error().size() << " error(s)\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    // 5) 组合：枚举不匹配 + 类型错配
    {
        Builder b;
        SchemaRule r1;
        r1.path = "mode";
        r1.enum_values = {std::string("dev"), std::string("prod")};
        SchemaRule r2;
        r2.path = "retries";
        r2.expected_type = SchemaValueType::Int64;
        r2.has_min = true;
        r2.min_value = 0;
        r2.has_max = true;
        r2.max_value = 3;
        b.add_schema_rule(r1).add_schema_rule(r2);
        b.set("mode", std::string("stage")); // 不在枚举
        b.set("retries", std::string("2"));  // 类型错配
        auto fr = b.freeze();
        if (!fr)
        {
            std::cerr << "Case EnumNotInSet/TypeMismatch: " << fr.error().size() << " error(s)\n";
            for (const auto & e : fr.error())
                print_error(e);
        }
    }

    std::cerr << "done.\n";
    return 0;
}
